with IO; use IO;
with Logging;
with Element;
with Interfaces; use Interfaces;
package body Parser is

   function New_Parser(File : IO.File_Type_Access) return Parser is
      Result : Parser;
   begin
      Result.File_Ptr := File;
      return Result;
   end New_Parser;

   procedure Parse_Rec(P : in Parser;
                       Size : in Stream_IO.Count;
                       Filter : in out Element_Filter_Interface'Class;
                       Depth : in Natural := 1) is
      Current_Element : Element_Type;
      use type Stream_IO.Positive_Count;
   begin
      -- base cases
      while Stream_IO.Index(P.File_Ptr.File) < Size loop
         Current_Element := NULL_Element_Type;

         Element_Type'Read(P.File_Ptr.File_Access, Current_Element);

         -- base cases
         if not Element.EBML_Element_Map.Contains(Current_Element.ID) then
            Logging.Warning("Unknown Element ID: " & Element_ID_Type'Image(Current_Element.ID));
            return;
         end if;

         Current_Element.EBML_Type := EBML_Element_Map.Element(Current_Element.ID);
         Current_Element.File_Index := Stream_IO.Index(P.File_Ptr.File);
         Current_Element.Depth := Depth;

         -- we found one
         Filter.Found_Element(E => Current_Element);

         -- first parse children
         if Current_Element.EBML_Type.Content = CONTAINER then
            Parse_Rec(P, Current_Element.File_End_Index, Filter, Depth + 1);
         end if;

         -- jump over and look in the rest for siblings
         Stream_IO.Set_Index(P.File_Ptr.File, Current_Element.File_End_Index);

      end loop;

   end Parse_Rec;

   procedure Parse(P : in Parser; Filter : in out Element_Filter_Interface'Class) is
      File_Size : Stream_IO.Count;
   begin
      Stream_IO.Set_Index(P.File_Ptr.File, 1); -- reset file
      File_Size := Stream_IO.Size(P.File_Ptr.File);
      Parse_Rec(P, File_Size, Filter);
   end Parse;

end Parser;